package com.example.musicplayer.service;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;

import com.example.musicplayer.ActivityStackManager;
import com.example.musicplayer.MusicPlayerApplication;
import com.example.musicplayer.R;
import com.example.musicplayer.activity.MainActivity;
import com.example.musicplayer.commonUtils.DisplayUtil;
import com.example.musicplayer.fragment.dialogFragment.MusicListDialogFragment;
import com.example.musicplayer.musicClass.MusicInfo;
import com.example.musicplayer.settings.MusicPlayerSettings;
import com.example.musicplayer.view.MusicPlayingProgressView;
import com.example.musicplayer.view.SlideLinearLayout;
import com.example.musicplayer.viewTools.ViewRotateAnimation;

public class MusicTabViewService extends Service {
    private static final int CLICK_EVENT_MIN_DELTA = 5;
    private static final int STANDARD_LOC_DELTA = 10;
    private static final int MSG_UPDATE_LOCATION = 1;
    private static final int ALPHA_ANIM_TIME = 50;
    private static final int SHOW_DELAY = 300;
    private static final float sAlphaDelta;
    private static int sMoveDelta;
    private static CallBackListener mCallBackListener;
    private static MusicTabViewStateListener sMusicTabViewStateListener;
    private final MusicTabViewBinder mBinder = new MusicTabViewBinder();
    private MusicService.MusicBinder mMusicBinder;
    private WindowManager mManager;
    private WindowManager.LayoutParams mParams;
    private ServiceHandler mServiceHandler;
    private View mView;
    private ViewRotateAnimation mRotateAnimation;
    private boolean mViewAdded = false;
    private boolean mCanMove = false;
    private boolean mIsMoving = false;
    private ImageView mBitmapImageView;
    private ImageView mImageViewPlayState;
    private ImageView mImageViewPlayList;
    private ImageView mCancelAdjust;
    private View mMusicInfoView;
    private MusicPlayingProgressView mProgressView;
    private MusicListDialogFragment mMusicListDialogFragment;
    private int mCurrentMusicIndex;
    private int mLastMusicIndex;
    private int mNextMusicIndex;
    private int mCurrentX;
    private int mCurrentY;
    private int mMinY = 0;
    private int mMaxY;
    private int mViewHeight;
    private int mStartMarginBottom;
    //flag to judge if appear or disappear
    private boolean mAnimationAppear = true;
    private final Handler mAppearHandler = new Handler();
    private final Runnable mAlphaAnimation = new Runnable() {
        @Override
        public void run() {
            float currentAlpha = mView.getAlpha();
            //if begin is not attached, let it be visible
            if (currentAlpha == 0.0f) {
                showMusicTabView(true);
            }
            if (mAnimationAppear) {
                currentAlpha = Math.min(1.0f, currentAlpha + sAlphaDelta);
            } else {
                currentAlpha = Math.max(0.0f, currentAlpha - sAlphaDelta);
            }
            mView.setAlpha(currentAlpha);
            if (currentAlpha > 0.0f && currentAlpha < 1.0f) {
                mAppearHandler.postDelayed(mAlphaAnimation, MusicPlayerApplication.getRefreshTime());
            } else if (currentAlpha == 0.0f) {
                showMusicTabView(false);
            } else {
                showMusicTabView(true);
            }
        }
    };

    static {
        sAlphaDelta = (float) MusicPlayerApplication.getRefreshTime() / (float) ALPHA_ANIM_TIME;
    }

    @SuppressLint("HandlerLeak")
    private class ServiceHandler extends Handler {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            if (msg.what == MSG_UPDATE_LOCATION) {
                updateViewLoc();
            }
        }
    }

    private class MoveThread extends Thread {

        @Override
        public void run() {
            while (true) {
                if (sMoveDelta != 0) {
                    mIsMoving = true;
                    mCurrentY += sMoveDelta;
                    if (sMoveDelta < 0) {
                        mCurrentY = Math.max(mCurrentY, 0);
                    } else {
                        mCurrentY = Math.min(mCurrentY, mStartMarginBottom);
                    }
                    mServiceHandler.sendEmptyMessage(MSG_UPDATE_LOCATION);
                    if (mCurrentY != 0 && mCurrentY != mStartMarginBottom) {
                        try {
                            Thread.sleep(MusicPlayerApplication.getRefreshTime());
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } else {
                        mIsMoving = false;
                        break;
                    }
                } else {
                    mIsMoving = false;
                    break;
                }
            }
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
        mParams = new WindowManager.LayoutParams();
        mServiceHandler = new ServiceHandler();
        createView();
        addListener();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        updateViewLoc();
        return Service.START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        showMusicTabView(false);
        mManager = null;
        mParams = null;
    }

    @SuppressLint({"InflateParams", "ClickableViewAccessibility"})
    private void createView() {
        mMusicListDialogFragment = new MusicListDialogFragment();
        mViewHeight = (int) getResources().getDimension(R.dimen.music_tab_view_height);
        Activity activity = ActivityStackManager.getInstance().getTopActivity();
        if (activity != null) {
            mMaxY = DisplayUtil.getRealScreenSize(activity)[1] - DisplayUtil.getStatusBarHeight(getResources()) - mViewHeight;
        }
        mStartMarginBottom = (int) getResources().getDimension(R.dimen.music_tab_view_margin_bottom);
        mView = LayoutInflater.from(this).inflate(R.layout.music_tab_view, null);
        mBitmapImageView = mView.findViewById(R.id.circle_imageview);
        mImageViewPlayState = mView.findViewById(R.id.imageview_music_state);
        mImageViewPlayList = mView.findViewById(R.id.imageview_music_list);
        mCancelAdjust = mView.findViewById(R.id.imageview_cancel_adjust);
        mMusicInfoView = mView.findViewById(R.id.music_info_area);
        mProgressView = mView.findViewById(R.id.music_playing_progress_view);
        int imageSize = (int) getResources().getDimension(R.dimen.music_tab_view_image_size);

        //add touch listen that can move this tav view
        MusicTabViewTouchListener touchListener = new MusicTabViewTouchListener();
        mView.setOnTouchListener(touchListener);
        mBitmapImageView.setOnTouchListener(touchListener);
        mMusicInfoView.setOnTouchListener(touchListener);
        mImageViewPlayState.setOnTouchListener(touchListener);
        mImageViewPlayList.setOnTouchListener(touchListener);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            mParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            mParams.type = WindowManager.LayoutParams.TYPE_PHONE;
        }
        //set not opaque
        mParams.format = PixelFormat.RGBA_8888;
        mParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
        mParams.width = WindowManager.LayoutParams.MATCH_PARENT;
        mParams.height = mViewHeight;
        mParams.gravity = Gravity.BOTTOM;
        mCurrentX = mParams.x = 0;
        mCurrentY = mParams.y = mStartMarginBottom;
    }

    private void addListener() {
        if (mMusicInfoView instanceof SlideLinearLayout) {
            ((SlideLinearLayout) mMusicInfoView).setSlideListener(new SlideLinearLayout.SlideListener() {
                @Override
                public void startAutoScroll(boolean isSlideLeft, boolean isSlideRight) {

                }

                @Override
                public void endAutoScroll(boolean isSlideLeft, boolean isSlideRight) {
                    String textInfo = null;
                    if (isSlideLeft) {
                        textInfo = (String) ((TextView) mView.findViewById(R.id.textview_music_info_last)).getText();
                    } else if (isSlideRight) {
                        textInfo = (String) ((TextView) mView.findViewById(R.id.textview_music_info_next)).getText();
                    }
                    if ((isSlideLeft || isSlideRight) && textInfo != null && mMusicBinder != null) {
                        ((TextView) mView.findViewById(R.id.textview_music_info)).setText(textInfo);
                        ((TextView) mView.findViewById(R.id.textview_music_info_last)).setText(textInfo);
                        ((TextView) mView.findViewById(R.id.textview_music_info_next)).setText(textInfo);
                        ((SlideLinearLayout) mMusicInfoView).resumeWithNoAnim();
                        if (isSlideLeft) {
                            mMusicBinder.startLast();
                        } else {
                            mMusicBinder.startNext();
                        }
                    }
                }
            });
        }
        mBitmapImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!mCanMove && mCallBackListener != null && mMusicBinder != null && mMusicBinder.getMusicCounts() > 0) {
                    mCallBackListener.jumpToMusicPlayActivity();
                }
            }
        });
        mMusicInfoView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!mCanMove && mCallBackListener != null && mMusicBinder != null && mMusicBinder.getMusicCounts() > 0) {
                    mCallBackListener.jumpToMusicPlayActivity();
                }
            }
        });
        mBitmapImageView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                if (!mCanMove) {
                    setAdjustMode(true);
                }
                return true;
            }
        });
        mMusicInfoView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                if (!mCanMove) {
                    setAdjustMode(true);
                }
                return true;
            }
        });
        mImageViewPlayState.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!mCanMove && mMusicBinder != null) {
                    mMusicBinder.changePlayingState();
                }
            }
        });
        mImageViewPlayList.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!mCanMove && mCallBackListener != null && mMusicBinder != null && mMusicBinder.getMusicCounts() > 0
                        && !mMusicListDialogFragment.isAdded()) {
                    mCallBackListener.showMusicList(mMusicListDialogFragment);
                }
            }
        });
        mCancelAdjust.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                setAdjustMode(false);
            }
        });
        mMusicListDialogFragment.setCallBackListener(new MusicListDialogFragment.CallBackListener() {
            @Override
            public MusicService.MusicBinder getBinder() {
                return mMusicBinder;
            }

            @Override
            public void onMusicListShow() {
                appear(false);
            }

            @Override
            public void onMusicListDismiss() {
                appear(true);
            }
        });
    }

    private void setupRotationAnimation() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                if (mRotateAnimation == null) {
                    mRotateAnimation = new ViewRotateAnimation(mBitmapImageView, ViewRotateAnimation.ROTATION_Z
                            , 0, 360);
                    mRotateAnimation.setDuration(60000);
                    mRotateAnimation.setPivotX(mBitmapImageView.getWidth() / 2);
                    mRotateAnimation.setPivotY(mBitmapImageView.getHeight() / 2);
                    mRotateAnimation.setRepeatCount(-1);
                    mRotateAnimation.setInterpolator(new LinearInterpolator());
                    if (mMusicBinder != null && mMusicBinder.isPlaying()) {
                        mRotateAnimation.start();
                    }
                }
            }
        }, SHOW_DELAY + 300);
    }

    private void updateViewLoc() {
        mCurrentY = Math.max(mCurrentY, mMinY);
        mCurrentY = Math.min(mCurrentY, mMaxY);
        //judge the standard location
        int standardY = getStandardLocY();
        if (Math.abs(mCurrentY - standardY) <= STANDARD_LOC_DELTA) {
            mCurrentY = standardY;
        }
        mParams.x = mCurrentX;
        mParams.y = mCurrentY;
        if (mViewAdded) {
            mManager.updateViewLayout(mView, mParams);
        }
    }

    private void updateMusicTab() {
        if (mMusicBinder != null) {
            if (mMusicBinder.hasMusic()) {
                //could slide left or right
                if (mMusicInfoView instanceof SlideLinearLayout) {
                    ((SlideLinearLayout) mMusicInfoView).setCanSlideHorizontal(true);
                }
                Bitmap bitmap = mMusicBinder.getAlbumBitmap();
                if (bitmap == null) {
                    mBitmapImageView.setImageResource(R.mipmap.default1);
                } else {
                    mBitmapImageView.setImageBitmap(bitmap);
                }
                //current music info
                TextView textViewInfo = mView.findViewById(R.id.textview_music_info);
                String title = mMusicBinder.getTitle();
                String artist = mMusicBinder.getArtist();
                String textViewMusicInfo = title + " - " + artist;
                textViewInfo.setText(textViewMusicInfo);
                textViewInfo.setTextColor(getResources().getColor(R.color.black));
                mImageViewPlayList.setImageResource(R.drawable.main_activity_play_list);
                //last music info
                textViewInfo = mView.findViewById(R.id.textview_music_info_last);
                MusicInfo musicInfo = mMusicBinder.getMusicInfo(mLastMusicIndex);
                if (musicInfo != null) {
                    title = musicInfo.getTitle();
                    artist = musicInfo.getArtist();
                    textViewMusicInfo = title + " - " + artist;
                    textViewInfo.setText(textViewMusicInfo);
                }
                //next music info
                textViewInfo = mView.findViewById(R.id.textview_music_info_next);
                musicInfo = mMusicBinder.getMusicInfo(mNextMusicIndex);
                if (musicInfo != null) {
                    title = musicInfo.getTitle();
                    artist = musicInfo.getArtist();
                    textViewMusicInfo = title + " - " + artist;
                    textViewInfo.setText(textViewMusicInfo);
                }
            } else {
                //could not slide left or right
                if (mMusicInfoView instanceof SlideLinearLayout) {
                    ((SlideLinearLayout) mMusicInfoView).setCanSlideHorizontal(false);
                }
                TextView textViewInfo = mView.findViewById(R.id.textview_music_info);
                mBitmapImageView.setImageResource(R.mipmap.default1);
                textViewInfo.setText(R.string.main_activity_music_info);
                textViewInfo.setTextColor(getResources().getColor(R.color.light_gray));
                mImageViewPlayList.setImageResource(R.drawable.main_activity_no_list);
                if (mRotateAnimation != null) {
                    mRotateAnimation.cancel();
                    mBitmapImageView.setRotation(0f);
                }
            }
            updatePlayingStateChanged();
        }
    }

    //当播放状态变化时调用
    private void updatePlayingStateChanged() {
        if (mMusicBinder.hasMusic()) {
            mProgressView.setColorEnable(true);
            setImageViewMusicState(true, mMusicBinder.isPlaying());
            if (mRotateAnimation == null) {
                setupRotationAnimation();
            } else {
                if (mMusicBinder.isPlaying()) {
                    if (mRotateAnimation.isStarted()) {
                        mRotateAnimation.resume();
                    } else {
                        mRotateAnimation.start();
                    }
                } else {
                    if (mRotateAnimation.isStarted()) {
                        mRotateAnimation.pause();
                    }
                }
            }
        } else {
            setImageViewMusicState(false, true);
            mProgressView.setColorEnable(false);
        }
        updateProgressView();
    }

    //更新进度条
    private void updateProgressView() {
        //更新圆形播放进度条
        if (mMusicBinder != null) {
            float duration = (float) mMusicBinder.getDuration();
            if (duration > 0) {
                float sweepAngle = (float) mMusicBinder.getCurrent() / duration * 360;
                mProgressView.setSweepAngle(sweepAngle);
            }
        }
    }

    //改变播放图标
    private void setImageViewMusicState(boolean hasMusic, boolean state) {
        if (!hasMusic) {
            mImageViewPlayState.setImageResource(R.drawable.main_activity_no_playings);
        } else if (state) {
            mImageViewPlayState.setImageResource(R.drawable.main_activity_playings);
        } else {
            mImageViewPlayState.setImageResource(R.drawable.main_activity_pauses);
        }
    }

    private void showMusicTabView(boolean show) {
        if (mManager != null) {
            if (show && !mViewAdded) {
                mManager.addView(mView, mParams);
                mViewAdded = true;
                if (sMusicTabViewStateListener != null) {
                    sMusicTabViewStateListener.onViewStateChanged(true);
                }
                updateViewLoc();
            }
            if (!show && mViewAdded) {
                mManager.removeView(mView);
                mViewAdded = false;
                if (sMusicTabViewStateListener != null) {
                    sMusicTabViewStateListener.onViewStateChanged(false);
                }
            }
        }
    }

    private void appear(boolean appear) {
        mAnimationAppear = appear;
        if (MusicPlayerSettings.isAnimEffect()) {
            if (mAnimationAppear) {
                mAppearHandler.postDelayed(mAlphaAnimation, SHOW_DELAY);
            } else {
                showMusicTabView(appear);
            }
        } else {
            showMusicTabView(appear);
        }
    }

    private void moveToBottom(boolean moveToBottom) {
        if (!mCanMove) {
            if (MusicPlayerSettings.isAnimEffect()) {
                //enable animation
                int counts = MusicPlayerApplication.getAnimationTime() / MusicPlayerApplication.getRefreshTime();
                if (moveToBottom) {
                    if (mCurrentY != mStartMarginBottom && !mIsMoving) {
                        return;
                    }
                    sMoveDelta = (-mCurrentY) / counts;
                    if (sMoveDelta == 0) {
                        mCurrentY = 0;
                        updateViewLoc();
                    }
                } else {
                    if (mCurrentY != 0 && !mIsMoving) {
                        return;
                    }
                    sMoveDelta = (mStartMarginBottom - mCurrentY) / counts;
                    if (sMoveDelta == 0) {
                        mCurrentY = mStartMarginBottom;
                        updateViewLoc();
                    }
                }
                if (sMoveDelta != 0) {
                    if (!mIsMoving) {
                        new MoveThread().start();
                    }
                }
            } else {
                if (moveToBottom) {
                    mCurrentY = 0;
                } else {
                    mCurrentY = mStartMarginBottom;
                }
                updateViewLoc();
            }
        }
    }

    private void setAdjustMode(boolean isAdjustMode) {
        mCanMove = isAdjustMode;
        View mContainerView = mView.findViewById(R.id.linear_layout_container);
        if (mCanMove) {
            mCancelAdjust.setVisibility(View.VISIBLE);
            mContainerView.setBackgroundResource(R.drawable.music_tab_view_background_adjust);
        } else {
            mCancelAdjust.setVisibility(View.GONE);
            mContainerView.setBackgroundResource(R.drawable.music_tab_view_background);
        }
        //set if music info view can slide
        if (mMusicInfoView instanceof SlideLinearLayout) {
            ((SlideLinearLayout) mMusicInfoView).setCanSlideHorizontal(!mCanMove && mMusicBinder != null && mMusicBinder.hasMusic());
        }
    }

    private int getStandardLocY() {
        if (MusicPlayerApplication.getInstance().getTopActivity() instanceof MainActivity) {
            return mStartMarginBottom;
        } else {
            return 0;
        }
    }

    public static void setCallBackListener(CallBackListener listener) {
        mCallBackListener = listener;
    }

    public static void removeCallBackListener() {
        mCallBackListener = null;
    }

    public static void setMusicTabViewStateListener(MusicTabViewStateListener listener) {
        sMusicTabViewStateListener = listener;
    }

    public static void removeMusicTabViewStateListener() {
        sMusicTabViewStateListener = null;
    }

    private class MusicTabViewTouchListener implements View.OnTouchListener {
        private int mStartTouchY;
        private int mStartLayoutY;
        private int mStartRelativeX;
        private int mStartRelativeY;
        private boolean mShouldPerformClick = true;
        //flag to judge if execute touch event
        private boolean mHasDownEvent = false;

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (!mCanMove) {
                mHasDownEvent = false;
                return false;
            }
            if (event.getAction() != MotionEvent.ACTION_DOWN && !mHasDownEvent) {
                return false;
            }
            int y = (int) event.getRawY();
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mStartTouchY = y;
                    mStartLayoutY = mCurrentY;
                    mStartRelativeX = (int) event.getX();
                    mStartRelativeY = (int) event.getY();
                    mShouldPerformClick = true;
                    mHasDownEvent = true;
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (mShouldPerformClick) {
                        int relativeX = (int) event.getX();
                        int relativeY = (int) event.getY();
                        mShouldPerformClick = relativeX >= 0 && relativeX <= v.getMeasuredWidth()
                                && relativeY >= 0 && relativeY <= v.getMeasuredHeight()
                                && Math.abs(relativeX - mStartRelativeX) <= CLICK_EVENT_MIN_DELTA
                                && Math.abs(relativeY - mStartRelativeY) <= CLICK_EVENT_MIN_DELTA;
                    }
                    if (!mShouldPerformClick) {
                        int dy = y - mStartTouchY;
                        mCurrentY = mStartLayoutY - dy;
                        updateViewLoc();
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    if (mShouldPerformClick) {
                        v.performClick();
                    }
                    break;
                case MotionEvent.ACTION_CANCEL:
                    break;
            }
            if (event.getAction() != MotionEvent.ACTION_DOWN && event.getAction() != MotionEvent.ACTION_MOVE) {
                mHasDownEvent = false;
            }
            return true;
        }
    }

    public class MusicTabViewBinder extends Binder {
        public void setMusicBinder(MusicService.MusicBinder musicBinder) {
            mMusicBinder = musicBinder;
            updateMusicTab();
        }

        public void refreshView() {
            if (mMusicBinder != null) {
                updateProgressView();
                if (mCurrentMusicIndex != mMusicBinder.getNowMusicPosition()
                        || mLastMusicIndex != mMusicBinder.getLastMusicPosition()
                        || mNextMusicIndex != mMusicBinder.getNextMusicPosition()) {
                    updateMusicTab();
                }
            }
        }

        public void updateMusicTab() {
            //init the music index
            if (mMusicBinder != null) {
                mCurrentMusicIndex = mMusicBinder.getNowMusicPosition();
                mLastMusicIndex = mMusicBinder.getLastMusicPosition();
                mNextMusicIndex = mMusicBinder.getNextMusicPosition();
            }
            MusicTabViewService.this.updateMusicTab();
        }

        public void updatePlayingState() {
            updatePlayingStateChanged();
        }

        public void updatePlayModeChanged() {
            updateMusicTab();
        }

        public void shouldShowView(boolean shouldShow) {
            appear(shouldShow);
        }

        public void shouldMoveView(boolean moveToBottom) {
            moveToBottom(moveToBottom);
        }

        public void updateMusicListView() {
            if (mMusicListDialogFragment != null && mMusicListDialogFragment.isResumed()) {
                mMusicListDialogFragment.updateWhenChangingMusic();
            }
        }

        public boolean isViewAdded() {
            return mViewAdded;
        }

        public void showViewDirectly(boolean show) {
            showMusicTabView(false);
        }
    }

    public static interface CallBackListener {
        //try to show current music list
        void showMusicList(MusicListDialogFragment musicListDialogFragment);

        //jump to music play activity
        void jumpToMusicPlayActivity();
    }

    public static interface MusicTabViewStateListener {
        void onViewStateChanged(boolean isAdded);
    }
}